home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
usenet
/
sources
/
volume89
/
comm
/
amigatcp.3
< prev
next >
Wrap
Text File
|
1989-03-18
|
43KB
|
1,827 lines
Path: xanth!ukma!mailrus!ulowell!page
From: page@swan.ulowell.edu (Bob Page)
Newsgroups: comp.sources.amiga
Subject: v89i082: amigatcp - tcp/ip for the amiga, Part03/06
Message-ID: <12330@swan.ulowell.edu>
Date: 17 Mar 89 23:17:43 GMT
Organization: University of Lowell, Computer Science Dept.
Lines: 1816
Approved: page@swan.ulowell.edu
Submitted-by: rminnich@super.org (Ronald G. Minnich)
Posting-number: Volume 89, Issue 82
Archive-name: comm/amigatcp.3
# This is a shell archive.
# Remove everything above and including the cut line.
# Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# ftpserv.c
# tcpsubr.c
# ip.c
# udp.c
# This archive created: Fri Mar 17 17:57:41 1989
cat << \SHAR_EOF > ftpserv.c
/* FTP Server state machine - see RFC 959 */
#define LINELEN 128 /* Length of command buffer */
#include <stdio.h>
#include "machdep.h"
#include "mbuf.h"
#include "netuser.h"
#include "timer.h"
#include "tcp.h"
#include "ftp.h"
/* Command table */
static char *commands[] = {
"user",
#define USER_CMD 0
"acct",
#define ACCT_CMD 1
"pass",
#define PASS_CMD 2
"type",
#define TYPE_CMD 3
"list",
#define LIST_CMD 4
"cwd",
#define CWD_CMD 5
"dele",
#define DELE_CMD 6
"name",
#define NAME_CMD 7
"quit",
#define QUIT_CMD 8
"retr",
#define RETR_CMD 9
"stor",
#define STOR_CMD 10
"port",
#define PORT_CMD 11
"nlst",
#define NLST_CMD 12
"pwd",
#define PWD_CMD 13
"xpwd", /* For compatibility with 4.2BSD */
#define XPWD_CMD 14
NULLCHAR
};
/* Response messages */
static char banner[] = "220 %s FTP Ready\r\n";
static char badcmd[] = "500 Unknown command\r\n";
static char nopass[] = "202 Password not needed\r\n";
static char logged[] = "230 Logged in\r\n";
static char typeok[] = "200 Type OK\r\n";
static char cwdok[] = "250 CWD OK\r\n";
static char pwdmsg[] = "257 \"%s\" is current directory\r\n";
static char badtype[] = "501 Unknown type\r\n";
static char badport[] = "501 Bad port syntax\r\n";
static char unimp[] = "502 Command not yet implemented\r\n";
static char bye[] = "221 Goodbye!\r\n";
static char nodir[] = "553 Can't read directory\r\n";
static char cantopen[] = "550 Can't open file\r\n";
static char sending[] = "150 Opening data connection for %s %s\r\n";
static char cantmake[] = "553 Can't create file\r\n";
static char portok[] = "200 Port command okay\r\n";
static char rxok[] = "226 File received OK\r\n";
static char txok[] = "226 File sent OK\r\n";
static struct tcb *ftp_tcb;
/* Start up FTP service */
ftp_start(argc,argv)
int argc;
char *argv[];
{
struct socket lsocket;
void r_ftp(),s_ftp();
lsocket.address = ip_addr;
if(argc < 2)
lsocket.port = FTP_PORT;
else
lsocket.port = atoi(argv[1]);
ftp_tcb = open_tcp(&lsocket,NULLSOCK,TCP_PASSIVE,0,r_ftp,NULLVFP,s_ftp,0,(int *)NULL);
}
ftp_stop()
{
if(ftp_tcb != NULLTCB)
close_tcp(ftp_tcb);
}
/* FTP server control channel connection state change upcall handler */
static
void
s_ftp(tcb,old,new)
struct tcb *tcb;
char old,new;
{
extern char hostname[];
struct ftp *ftp,*ftp_create();
void ftp_delete();
char *inet_ntoa(),*pwd();
switch(new){
#ifdef QUICKSTART
case SYN_RECEIVED:
#else
case ESTABLISHED:
#endif
if((ftp = ftp_create(LINELEN)) == NULLFTP){
/* No space, kill connection */
close_tcp(tcb);
return;
}
ftp->control = tcb; /* Downward link */
tcb->user = (int *)ftp; /* Upward link */
/* Set default data port */
ftp->port.address = tcb->conn.remote.address;
ftp->port.port = FTPD_PORT;
/* Note current directory */
#ifndef AMIGA
ftp->cd = pwd();
#endif
log(tcb,"open FTP");
tprintf(ftp->control,banner,hostname);
break;
case CLOSE_WAIT:
close_tcp(tcb);
break;
case CLOSED:
log(tcb,"close FTP");
if((ftp = (struct ftp *)tcb->user) != NULLFTP)
ftp_delete(ftp);
/* Check if server is being shut down */
if(tcb == ftp_tcb)
ftp_tcb = NULLTCB;
del_tcp(tcb);
break;
}
}
/* FTP control channel receiver upcall handler */
static
void
r_ftp(tcb,cnt)
struct tcb *tcb;
int16 cnt;
{
register struct ftp *ftp;
char *index(),c;
struct mbuf *bp;
void docommand();
if((ftp = (struct ftp *)tcb->user) == NULLFTP){
/* Unknown connection, just kill it */
close_tcp(tcb);
return;
}
switch(ftp->state){
case COMMAND_STATE:
/* Assemble an input line in the session buffer. Return if incomplete */
recv_tcp(tcb,&bp,0);
while(pullup(&bp,&c,1) == 1){
switch(c){
case '\r': /* Strip cr's */
continue;
case '\n': /* Complete line; process it */
ftp->buf[ftp->cnt] = '\0';
docommand(ftp);
ftp->cnt = 0;
break;
default: /* Assemble line */
if(ftp->cnt != LINELEN-1)
ftp->buf[ftp->cnt++] = c;
break;
}
}
/* else no linefeed present yet to terminate command */
break;
case SENDING_STATE:
case RECEIVING_STATE:
/* Leave commands pending on receive queue until
* present command is done
*/
break;
}
}
/* FTP server data channel connection state change upcall handler */
void
s_ftpd(tcb,old,new)
struct tcb *tcb;
char old,new;
{
struct ftp *ftp;
#ifndef CPM
#ifndef AMIGA
char *cdsave;
#endif
#endif
if((ftp = (struct ftp *)tcb->user) == NULLFTP){
/* Unknown connection, kill it */
close_tcp(tcb);
return;
}
switch(new){
case FINWAIT2:
case TIME_WAIT:
if(ftp != NULLFTP && ftp->state == SENDING_STATE){
/* We've received an ack of our FIN, so
* send a completion message on the control channel
*/
ftp->state = COMMAND_STATE;
tprintf(ftp->control,txok);
/* Kick command parser if something is waiting */
if(ftp->control->rcvcnt != 0)
r_ftp(ftp->control,ftp->control->rcvcnt);
}
break;
case CLOSE_WAIT:
close_tcp(tcb);
if(ftp != NULLFTP && ftp->state == RECEIVING_STATE){
/* End of file received on incoming file */
#ifdef CPM
if(ftp->type == ASCII_TYPE)
putc(CTLZ,ftp->fp);
#endif
#ifndef CPM
#ifndef AMIGA
cdsave = pwd(); /* Save current directory */
chdir(ftp->cd); /* Switch to user's directory*/
#endif
#endif
fclose(ftp->fp);
#ifndef CPM
#ifndef AMIGA
if(cdsave != NULLCHAR){
chdir(cdsave); /* And back */
free(cdsave);
}
#endif
#endif
ftp->fp = NULLFILE;
ftp->state = COMMAND_STATE;
tprintf(ftp->control,rxok);
/* Kick command parser if something is waiting */
if(ftp->control->rcvcnt != 0)
r_ftp(ftp->control,ftp->control->rcvcnt);
}
break;
case CLOSED:
if(ftp != NULLFTP)
ftp->data = NULLTCB;
del_tcp(tcb);
break;
}
}
/* Parse and execute ftp commands */
static
void
docommand(ftp)
register struct ftp *ftp;
{
void r_ftpd(),t_ftpd(),s_ftpd();
char *cmd,*arg,*cp,**cmdp;
char *index(),*malloc(),*strcpy();
struct socket dport;
#ifndef CPM
#ifndef AMIGA
FILE *dir();
char *cdsave;
#endif
#endif
cmd = ftp->buf;
if(ftp->cnt == 0){
/* Can't be a legal FTP command */
tprintf(ftp->control,badcmd);
return;
}
cmd = ftp->buf;
/* Translate entire buffer to lower case */
for(cp = cmd;*cp != '\0';cp++)
*cp = tolower(*cp);
/* Find command in table; if not present, return syntax error */
for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
if(strncmp(*cmdp,cmd,strlen(*cmdp)) == 0)
break;
if(*cmdp == NULLCHAR){
tprintf(ftp->control,badcmd);
return;
}
arg = &cmd[strlen(*cmdp)];
while(*arg == ' ')
arg++;
/* Execute specific command */
switch(cmdp-commands){
case USER_CMD:
if((ftp->username = malloc((unsigned)strlen(arg)+1)) == NULLCHAR){
close_tcp(ftp->control);
break;
}
strcpy(ftp->username,arg);
tprintf(ftp->control,logged);
break;
case TYPE_CMD:
switch(*arg){
case 'a': /* Ascii */
ftp->type = ASCII_TYPE;
tprintf(ftp->control,typeok);
break;
case 'b': /* Binary */
case 'i': /* Image */
ftp->type = IMAGE_TYPE;
tprintf(ftp->control,typeok);
break;
default: /* Invalid */
tprintf(ftp->control,badtype);
break;
}
break;
case QUIT_CMD:
tprintf(ftp->control,bye);
close_tcp(ftp->control);
break;
case RETR_CMD:
/* Disk operation; return ACK now */
tcp_output(ftp->control);
#ifndef CPM
#ifndef AMIGA
cdsave = pwd(); /* Save current directory */
chdir(ftp->cd); /* Switch to user's directory*/
#endif
#endif
ftp->fp = fopen(arg,"r");
#ifndef CPM
#ifndef AMIGA
chdir(cdsave); /* And back */
free(cdsave);
#endif
#endif
if(ftp->fp == NULLFILE){
tprintf(ftp->control,cantopen);
} else {
log(ftp->control,"RETR %s/%s",ftp->cd,arg);
dport.address = ip_addr;
dport.port = FTPD_PORT;
ftp->state = SENDING_STATE;
tprintf(ftp->control,sending,"RETR",arg);
/* This hack is just so we can talk to ourselves */
ftp->data = open_tcp(&dport,&ftp->port,TCP_PASSIVE,
0,NULLVFP,t_ftpd,s_ftpd,ftp->control->tos,(int *)ftp);
ftp->data = open_tcp(&dport,&ftp->port,TCP_ACTIVE,
0,NULLVFP,t_ftpd,s_ftpd,ftp->control->tos,(int *)ftp);
}
break;
case STOR_CMD:
/* Disk operation; return ACK now */
tcp_output(ftp->control);
#ifndef CPM
#ifndef AMIGA
cdsave = pwd(); /* Save current directory */
chdir(ftp->cd); /* Switch to user's directory */
#endif
#endif
ftp->fp = fopen(arg,"w");
#ifndef CPM
#ifndef AMIGA
chdir(cdsave); /* And back */
free(cdsave);
#endif
#endif
if(ftp->fp == NULLFILE){
tprintf(ftp->control,cantmake);
} else {
log(ftp->control,"STOR %s/%s",ftp->cd,arg);
dport.address = ip_addr;
dport.port = FTPD_PORT;
ftp->state = RECEIVING_STATE;
tprintf(ftp->control,sending,"STOR",arg);
/* This hack is just so we can talk to ourselves */
ftp->data = open_tcp(&dport,&ftp->port,TCP_PASSIVE,
0,r_ftpd,NULLVFP,s_ftpd,ftp->control->tos,(int *)ftp);
ftp->data = open_tcp(&dport,&ftp->port,TCP_ACTIVE,
0,r_ftpd,NULLVFP,s_ftpd,ftp->control->tos,(int *)ftp);
}
break;
case PORT_CMD:
if(pport(&ftp->port,arg) == -1){
tprintf(ftp->control,badport);
} else {
tprintf(ftp->control,portok);
}
break;
/* #ifndef CPM */
#ifndef AMIGA
case LIST_CMD:
/* Disk operation; return ACK now */
tcp_output(ftp->control);
cdsave = pwd(); /* Save current directory */
chdir(ftp->cd); /* Switch to user's directory */
ftp->fp = dir(arg,1);
chdir(cdsave); /* And back */
free(cdsave);
if(ftp->fp == NULLFILE){
tprintf(ftp->control,nodir);
break;
}
dport.address = ip_addr;
dport.port = FTPD_PORT;
ftp->state = SENDING_STATE;
tprintf(ftp->control,sending,"LIST",arg);
/* This hack is just so we can talk to ourselves */
ftp->data = open_tcp(&dport,&ftp->port,TCP_PASSIVE,
0,NULLVFP,t_ftpd,s_ftpd,ftp->control->tos,(int *)ftp);
ftp->data = open_tcp(&dport,&ftp->port,TCP_ACTIVE,
0,NULLVFP,t_ftpd,s_ftpd,ftp->control->tos,(int *)ftp);
break;
case NLST_CMD:
/* Disk operation; return ACK now */
tcp_output(ftp->control);
cdsave = pwd(); /* Save current directory */
chdir(ftp->cd); /* Switch to user's directory */
ftp->fp = dir(arg,0);
chdir(cdsave); /* And back */
free(cdsave);
if(ftp->fp == NULLFILE){
tprintf(ftp->control,nodir);
break;
}
dport.address = ip_addr;
dport.port = FTPD_PORT;
ftp->state = SENDING_STATE;
tprintf(ftp->control,sending,"NLST",arg);
/* This hack is just so we can talk to ourselves */
ftp->data = open_tcp(&dport,&ftp->port,TCP_PASSIVE,
0,NULLVFP,t_ftpd,s_ftpd,ftp->control->tos,(int *)ftp);
ftp->data = open_tcp(&dport,&ftp->port,TCP_ACTIVE,
0,NULLVFP,t_ftpd,s_ftpd,ftp->control->tos,(int *)ftp);
break;
case CWD_CMD:
tcp_output(ftp->control); /* Disk operation; return ACK now */
cdsave = pwd(); /* Save current directory */
chdir(ftp->cd); /* Go to user's context */
if(chdir(arg) == 0){ /* Attempt switch */
/* Succeeded, record in control block */
free(ftp->cd);
ftp->cd = pwd();
tprintf(ftp->control,cwdok);
} else {
/* Failed, don't change anything */
tprintf(ftp->control,nodir);
}
chdir(cdsave); /* Go back */
free(cdsave);
break;
case XPWD_CMD:
case PWD_CMD:
tprintf(ftp->control,pwdmsg,ftp->cd);
break;
#else
case LIST_CMD:
case NLST_CMD:
case CWD_CMD:
case XPWD_CMD:
case PWD_CMD:
#endif
case ACCT_CMD:
case DELE_CMD:
tprintf(ftp->control,unimp);
break;
case PASS_CMD:
tprintf(ftp->control,nopass);
break;
}
}
static
int
pport(sock,arg)
struct socket *sock;
char *arg;
{
int32 n;
int atoi(),i;
n = 0;
for(i=0;i<4;i++){
n = atoi(arg) + (n << 8);
if((arg = index(arg,',')) == NULLCHAR)
return -1;
arg++;
}
sock->address = n;
n = atoi(arg);
if((arg = index(arg,',')) == NULLCHAR)
return -1;
arg++;
n = atoi(arg) + (n << 8);
sock->port = n;
return 0;
}
SHAR_EOF
cat << \SHAR_EOF > tcpsubr.c
#ifdef TRACE
#include <stdio.h>
#endif
#include "machdep.h"
#include "timer.h"
#include "mbuf.h"
#include "netuser.h"
#include "internet.h"
#include "tcp.h"
struct tcb *tcbs[NTCB];
/* Lookup connection, return TCB pointer or NULLTCB if nonexistant */
struct tcb *
lookup_tcb(conn)
struct connection *conn;
{
register struct tcb *tcb;
int16 hash_tcb();
tcb = tcbs[hash_tcb(conn)];
while(tcb != NULLTCB){
/* Yet another structure compatibility hack */
if(conn->local.address == tcb->conn.local.address
&& conn->remote.address == tcb->conn.remote.address
&& conn->local.port == tcb->conn.local.port
&& conn->remote.port == tcb->conn.remote.port)
break;
tcb = tcb->next;
}
return tcb;
}
/* Create a TCB, return pointer. Return pointer if TCB already exists. */
struct tcb *
create_tcb(conn)
struct connection *conn;
{
char *calloc();
register struct tcb *tcb;
void tcp_timeout(),tcp_msl();
void link_tcb();
if((tcb = lookup_tcb(conn)) != NULLTCB)
return tcb;
if((tcb = (struct tcb *)calloc(1,sizeof (struct tcb))) == NULLTCB)
return NULLTCB;
bcopy((char *)conn,(char *)&tcb->conn,sizeof(struct connection));
tcb->mss = DEF_MSS;
tcb->srtt = DEF_RTT * MSPTICK;
/* Initialize retransmission timeout */
tcb->timer.start = (BETA * tcb->srtt)/MSPTICK;
tcb->timer.func = tcp_timeout;
tcb->timer.arg = (int *)tcb;
link_tcb(tcb);
return tcb;
}
/* Close our TCB */
void
close_self(tcb,reason)
register struct tcb *tcb;
char reason;
{
struct reseq *rp,*rp1;
stop_timer(&tcb->timer);
tcb->reason = reason;
/* Flush reassembly queue; nothing more can arrive */
for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
rp1 = rp->next;
free_p(rp->bp);
free((char *)rp);
}
tcb->reseq = NULLRESEQ;
setstate(tcb,CLOSED);
}
/* Determine initial sequence number */
#ifdef AMIGA
/*
* routine called at startup time with inital value of iss for system. This
* is probably based on the time or something
*/
static int32 seq;
void
setiss(initval)
int32 initval;
{
seq = initval;
}
#endif
int32
iss()
{
#ifndef AMIGA
static int32 seq;
#endif
seq += 250000;
return seq;
}
/* Sequence number comparisons
* Return true if x is between low and high inclusive,
* false otherwise
*/
int
seq_within(x,low,high)
register int32 x,low,high;
{
if(low <= high){
if(low <= x && x <= high)
return 1;
} else {
if(low >= x && x >= high)
return 1;
}
return 0;
}
int
seq_lt(x,y)
register int32 x,y;
{
return (long)(x-y) < 0;
}
int
seq_le(x,y)
register int32 x,y;
{
return (long)(x-y) <= 0;
}
int
seq_gt(x,y)
register int32 x,y;
{
return (long)(x-y) > 0;
}
int
seq_ge(x,y)
register int32 x,y;
{
return (long)(x-y) >= 0;
}
/* Hash a connect structure into the hash chain header array */
static int16
hash_tcb(conn)
struct connection *conn;
{
register int16 hval;
/* Compute hash function on connection structure */
hval = hiword(conn->remote.address);
hval ^= loword(conn->remote.address);
hval ^= hiword(conn->local.address);
hval ^= loword(conn->local.address);
hval ^= conn->remote.port;
hval ^= conn->local.port;
hval %= NTCB;
return hval;
}
/* Insert TCB at head of proper hash chain */
void
link_tcb(tcb)
register struct tcb *tcb;
{
register struct tcb **tcbhead;
int16 hash_tcb();
char i_state;
tcb->prev = NULLTCB;
i_state = disable();
tcbhead = &tcbs[hash_tcb(&tcb->conn)];
tcb->next = *tcbhead;
if(tcb->next != NULLTCB){
tcb->next->prev = tcb;
}
*tcbhead = tcb;
restore(i_state);
}
/* Remove TCB from whatever hash chain it may be on */
void
unlink_tcb(tcb)
register struct tcb *tcb;
{
register struct tcb **tcbhead;
int16 hash_tcb();
char i_state;
i_state = disable();
tcbhead = &tcbs[hash_tcb(&tcb->conn)];
if(*tcbhead == tcb)
*tcbhead = tcb->next; /* We're the first one on the chain */
if(tcb->prev != NULLTCB)
tcb->prev->next = tcb->next;
if(tcb->next != NULLTCB)
tcb->next->prev = tcb->prev;
restore(i_state);
}
void
setstate(tcb,newstate)
register struct tcb *tcb;
register char newstate;
{
register char oldstate;
oldstate = tcb->state;
tcb->state = newstate;
if(tcb->s_upcall){
(*tcb->s_upcall)(tcb,oldstate,newstate);
}
/* Notify the user that he can begin sending data */
if(tcb->t_upcall && newstate == ESTABLISHED){
(*tcb->t_upcall)(tcb,tcb->window - tcb->sndcnt);
}
}
#ifdef TRACE
/* TCP connection states */
char *tcpstates[] = {
"Closed",
"Listen",
"SYN sent",
"SYN received",
"Established",
"FIN wait 1",
"FIN wait 2",
"Close wait",
"Closing",
"Last ACK",
"Time wait"
};
/* TCP segment header flags */
char *tcpflags[] = {
"FIN", /* 0x01 */
"SYN", /* 0x02 */
"RST", /* 0x04 */
"PSH", /* 0x08 */
"ACK", /* 0x10 */
"URG" /* 0x20 */
};
/* TCP closing reasons */
char *reasons[] = {
"Normal",
"Reset",
"Timeout",
"ICMP"
};
/* Return 1 if arg is a valid TCB, 0 otherwise */
int
tcpval(tcb)
struct tcb *tcb;
{
register int i;
register struct tcb *tcb1;
for(i=0;i<NTCB;i++){
for(tcb1=tcbs[i];tcb1 != NULLTCB;tcb1 = tcb1->next){
if(tcb1 == tcb)
return 1;
}
}
return 0;
}
/* Dump TCP stats and summary of all TCBs
/* &TCB Rcv-Q Snd-Q Local socket Remote socket State
* 1234 0 0 xxx.xxx.xxx.xxx:xxxxx xxx.xxx.xxx.xxx:xxxxx Established
*/
int
tcpstat()
{
register int i;
register struct tcb *tcb;
char *psocket();
printf("conout %u conin %u reset out %u runt %u chksum err %u bdcsts %u\r\n",
tcp_stat.conout,tcp_stat.conin,tcp_stat.resets,tcp_stat.runt,
tcp_stat.checksum,tcp_stat.bdcsts);
#ifdef AMIGA
printf("&TCB Rcv-Q Snd-Q Local socket Remote socket State\r\n");
#else
printf("&TCB Rcv-Q Snd-Q Local socket Remote socket State\r\n");
#endif
for(i=0;i<NTCB;i++){
for(tcb=tcbs[i];tcb != NULLTCB;tcb = tcb->next){
#ifdef AMIGA
printf("%6lx%6u%6u ",(unsigned long)tcb,
tcb->rcvcnt,tcb->sndcnt);
#else
printf("%4x%6u%6u ",(int)tcb,tcb->rcvcnt,tcb->sndcnt);
#endif
printf("%-23s",psocket(&tcb->conn.local));
printf("%-23s",psocket(&tcb->conn.remote));
printf("%-s\r\n",tcpstates[tcb->state]);
}
}
fflush(stdout);
return 0;
}
/* Dump a TCP control block */
void
state_tcp(tcb)
struct tcb *tcb;
{
int32 sent,recvd;
if(tcb == NULLTCB)
return;
/* Compute total data sent and received; take out SYN and FIN */
sent = tcb->snd.una - tcb->iss; /* Acknowledged data only */
recvd = tcb->rcv.nxt - tcb->irs;
switch(tcb->state){
case LISTEN:
case SYN_SENT: /* Nothing received or acked yet */
sent = recvd = 0;
break;
case SYN_RECEIVED:
recvd--; /* Got SYN, no data acked yet */
sent = 0;
break;
case ESTABLISHED: /* Got and sent SYN */
case FINWAIT1: /* FIN not acked yet */
sent--;
recvd--;
break;
case FINWAIT2: /* Our SYN and FIN both acked */
sent -= 2;
recvd--;
break;
case CLOSE_WAIT: /* Got SYN and FIN, our FIN not yet acked */
case CLOSING:
case LAST_ACK:
sent--;
recvd -= 2;
break;
case TIME_WAIT: /* Sent and received SYN/FIN, all acked */
sent -= 2;
recvd -= 2;
break;
}
printf("Local: %s",psocket(&tcb->conn.local));
printf(" Remote: %s",psocket(&tcb->conn.remote));
printf(" State: %s\r\n",tcpstates[tcb->state]);
printf(" Init seq Unack Next WL1 WL2 Wind MSS Queue Total\r\n");
printf("Send:");
printf("%9lx",tcb->iss);
printf("%9lx",tcb->snd.una);
printf("%9lx",tcb->snd.nxt);
printf("%9lx",tcb->snd.wl1);
printf("%9lx",tcb->snd.wl2);
printf("%6u",tcb->snd.wnd);
printf("%6u",tcb->mss);
printf("%6u",tcb->sndcnt);
printf("%11lu\r\n",sent);
printf("Recv:");
printf("%9lx",tcb->irs);
printf(" ");
printf("%9lx",tcb->rcv.nxt);
printf(" ");
printf(" ");
printf("%6u",tcb->rcv.wnd);
printf(" ");
printf("%6u",tcb->rcvcnt);
printf("%11lu\r\n",recvd);
if(tcb->reseq != (struct reseq *)NULL){
register struct reseq *rp;
printf("Reassembly queue:\r\n");
for(rp = tcb->reseq;rp != (struct reseq *)NULL; rp = rp->next){
printf(" seq x%lx %u bytes\r\n",rp->seg.seq,rp->length);
}
}
printf("Retry %u",tcb->retry);
switch(tcb->timer.state){
case TIMER_STOP:
printf(" Timer stopped");
break;
case TIMER_RUN:
printf(" Timer running (%ld/%ld mS)",
(long)MSPTICK * (tcb->timer.start - tcb->timer.count),
(long)MSPTICK * tcb->timer.start);
break;
case TIMER_EXPIRE:
printf(" Timer expired");
}
printf(" Smoothed round trip time %ld mS\r\n",tcb->srtt);
fflush(stdout);
}
/* Dump a TCP segment header. Assumed to be in network byte order */
void
tcp_dump(bp,source,dest,check)
struct mbuf *bp;
int32 source,dest; /* IP source and dest addresses */
int check; /* 0 if checksum test is to be bypassed */
{
int hdr_len,i;
register struct tcp_header *tcph;
struct pseudo_header ph;
char tmpbuf;
if(bp == NULLBUF)
return;
/* If packet isn't in a single buffer, make a temporary copy and
* note the fact so we free it later
*/
if(bp->next != NULLBUF){
bp = copy_p(bp,len_mbuf(bp));
tmpbuf = 1;
} else
tmpbuf = 0;
tcph = (struct tcp_header *)bp->data;
hdr_len = hinibble(tcph->offset) * sizeof(int32);
printf("TCP: %u->%u Seq x%lx",
ntohs(tcph->source),ntohs(tcph->dest),
ntohl(tcph->seq),ntohl(tcph->ack));
if(tcph->flags & ACK)
printf(" Ack x%lx",ntohl(tcph->ack));
for(i=0;i<6;i++){
if(tcph->flags & 1 << i){
printf(" %s",tcpflags[i]);
}
}
printf(" Wnd %u",ntohs(tcph->wnd));
if(tcph->flags & URG)
printf(" UP x%x",ntohs(tcph->up));
if(hdr_len > sizeof(struct tcp_header)){
struct mss *mssp;
mssp = (struct mss *)(tcph + 1);
if(mssp->kind == MSS_KIND && mssp->length == MSS_LENGTH){
printf(" MSS %u",ntohs(mssp->mss));
}
}
/* Verify checksum */
if(check){
ph.source = source;
ph.dest = dest;
ph.protocol = TCP_PTCL;
ph.length = len_mbuf(bp);
ph.zero = 0;
if((i = cksum(&ph,bp,ph.length)) != 0)
printf(" CHECKSUM ERROR (%u)",i);
}
printf("\r\n");
if(tmpbuf)
free_p(bp);
}
#endif
SHAR_EOF
cat << \SHAR_EOF > ip.c
/* Upper half of IP, consisting of send/receive primitives, including
* fragment reassembly, for higher level protocols.
* Not needed when running as a standalone gateway.
*/
#define TLB 30 /* Reassembly limit time */
#include <stdio.h>
#include "machdep.h"
#include "mbuf.h"
#include "timer.h"
#include "internet.h"
#include "ip.h"
#include "icmp.h"
#include "iface.h"
int ip_recv(); /* Should be void, but C complains */
char *calloc(),*malloc();
char ip_ttl = MAXTTL; /* Default time-to-live for IP datagrams */
struct reasm *reasmq;
#define INSERT 0
#define APPEND 1
#define PREPEND 2
/* Send an IP datagram. Modeled after the example interface on p 32 of
* RFC 791
*/
void
ip_send(source,dest,protocol,tos,ttl,bp,length,id,df)
int32 source; /* source address */
int32 dest; /* Destination address */
char protocol; /* Protocol */
char tos; /* Type of service */
char ttl; /* Time-to-live */
struct mbuf *bp; /* Data portion of datagram */
int16 length; /* Optional length of data portion */
int16 id; /* Optional identification */
char df; /* Don't-fragment flag */
{
struct mbuf *hbp; /* mbuf containing IP header */
struct ip_header *iph; /* Pointer to IP header */
static int16 id_cntr; /* Datagram serial number */
int16 hdr_len; /* IP header length, bytes */
void ip_route(); /* Datagram router */
if(length == 0 && bp != NULLBUF)
length = len_mbuf(bp);
if(id == 0)
id = id_cntr++;
if(ttl == 0)
ttl = ip_ttl;
/* Allocate an mbuf for the IP header */
hdr_len = sizeof(struct ip_header);
if((hbp = alloc_mbuf(hdr_len)) == NULLBUF){
/* We really ought to source-quench the sender, but that would
* probably fail too.
*/
free_p(bp);
return;
}
hbp->cnt = hdr_len;
/* and fill it in */
iph = (struct ip_header *)hbp->data;
iph->v_ihl = (IPVERSION << 4) | (hdr_len/sizeof(int32));
iph->tos = tos;
iph->length = htons(hdr_len + length);
iph->id = htons(id);
if(df)
iph->fl_offs = htons(DF);
else
iph->fl_offs = 0;
iph->ttl = ttl;
iph->protocol = protocol;
iph->checksum = 0;
iph->source = htonl(source);
iph->dest = htonl(dest);
iph->checksum = cksum(NULLHEADER,hbp,hdr_len);
hbp->next = bp;
ip_route(hbp,0); /* Toss it to the router */
}
/* Reassemble incoming IP fragments and dispatch completed datagrams
* to the proper transport module
*/
int /* Should really be void */
ip_recv(bp,rxbroadcast)
struct mbuf *bp;
char rxbroadcast;
{
register struct ip_header *ipp; /* Pointer to original IP header */
struct ip_header ip; /* Extracted copy of header */
int16 ip_len; /* Length of IP header */
struct mbuf *fraghandle();
void (*recv)(); /* Function to call with completed datagram */
void tcp_input(),udp_input(),icmp_input();
ipp = (struct ip_header *)bp->data;
/* Initial check for protocols we can't handle */
switch(ipp->protocol & 0xff){
case TCP_PTCL:
recv = tcp_input;
break;
case UDP_PTCL:
recv = udp_input;
break;
case ICMP_PTCL:
recv = icmp_input;
break;
default:
/* Send an ICMP Protocol Unknown response... */
ip_stats.badproto++;
/* ...unless it's a broadcast */
if(!rxbroadcast)
icmp_output(bp,DEST_UNREACH,PROT_UNREACH,(union icmp_args *)NULL);
free_p(bp);
return;
}
ip_len = lonibble(ipp->v_ihl) * sizeof(int32);
/* Extract IP header */
pullup(&bp,(char *)&ip,ip_len);
/* Convert to host byte order */
ip.length = ntohs(ip.length) - ip_len; /* Length of data portion */
ip.id = ntohs(ip.id);
ip.fl_offs = ntohs(ip.fl_offs);
ip.source = ntohl(ip.source);
ip.dest = ntohl(ip.dest);
/* If we have a complete packet, call the next layer
* to handle the result
*/
if((bp = fraghandle(&ip,bp)) != NULLBUF)
(*recv)(bp,ip.protocol,ip.source,ip.dest,ip.tos,ip.length,rxbroadcast);
}
/* Process IP datagram fragments
* If datagram is complete, return it with ip->length containing its
* entire length; otherwise return NULLBUF
*/
static
struct mbuf *
fraghandle(ip,bp)
struct ip_header *ip; /* IP header, host byte order */
struct mbuf *bp; /* The fragment itself */
{
void ip_timeout(),freefrag(),free_reasm();
struct reasm *lookup_reasm(),*creat_reasm();
register struct reasm *rp; /* Pointer to reassembly descriptor */
struct frag *lastfrag,*nextfrag,*tfp,*newfrag();
struct mbuf *tbp;
int16 i;
int16 offset; /* Index of first byte in fragment */
int16 last; /* Index of first byte beyond fragment */
char mf; /* 1 if not last fragment, 0 otherwise */
offset = (ip->fl_offs & F_OFFSET) << 3; /* Convert to bytes */
last = offset + ip->length;
mf = (ip->fl_offs & MF) ? 1 : 0;
rp = lookup_reasm(ip);
if(offset == 0 && !mf){
/* Complete datagram received. Discard any earlier fragments */
if(rp != NULLREASM)
free_reasm(rp);
return bp;
}
if(rp == NULLREASM){
/* First fragment; create new reassembly descriptor */
if((rp = creat_reasm(ip)) == NULLREASM){
/* No space for descriptor, drop fragment */
free_p(bp);
return NULLBUF;
}
}
/* Keep restarting timer as long as we keep getting fragments */
stop_timer(&rp->timer);
start_timer(&rp->timer);
/* If this is the last fragment, we now know how long the
* entire datagram is; record it
*/
if(!mf)
rp->length = last;
/* Set nextfrag to the first fragment which begins after us,
* and lastfrag to the last fragment which begins before us
*/
lastfrag = NULLFRAG;
for(nextfrag = rp->fraglist;nextfrag != NULLFRAG;nextfrag = nextfrag->next){
if(nextfrag->offset > offset)
break;
lastfrag = nextfrag;
}
/* Check for overlap with preceeding fragment */
if(lastfrag != NULLFRAG && offset < lastfrag->last){
/* Strip overlap from new fragment */
i = lastfrag->last - offset;
pullup(&bp,NULLCHAR,i);
if(bp == NULLBUF)
return NULLBUF; /* Nothing left */
offset += i;
}
/* Look for overlap with succeeding segments */
for(; nextfrag != NULLFRAG; nextfrag = tfp){
tfp = nextfrag->next; /* save in case we delete fp */
if(nextfrag->offset >= last)
break; /* Past our end */
/* Trim the front of this entry; if nothing is
* left, remove it.
*/
i = last - nextfrag->offset;
pullup(&nextfrag->buf,NULLCHAR,i);
if(nextfrag->buf == NULLBUF){
/* superseded; delete from list */
if(nextfrag->prev != NULLFRAG)
nextfrag->prev->next = nextfrag->next;
else
rp->fraglist = nextfrag->next;
if(tfp->next != NULLFRAG)
nextfrag->next->prev = nextfrag->prev;
freefrag(nextfrag);
} else
nextfrag->offset = last;
}
/* Lastfrag now points, as before, to the fragment before us;
* nextfrag points at the next fragment. Check to see if we can
* join to either or both fragments.
*/
i = INSERT;
if(lastfrag != NULLFRAG && lastfrag->last == offset)
i |= APPEND;
if(nextfrag != NULLFRAG && nextfrag->offset == last)
i |= PREPEND;
switch(i){
case INSERT: /* Insert new desc between lastfrag and nextfrag */
tfp = newfrag(offset,last,bp);
tfp->prev = lastfrag;
tfp->next = nextfrag;
if(lastfrag != NULLFRAG)
lastfrag->next = tfp; /* Middle of list */
else
rp->fraglist = tfp; /* First on list */
if(nextfrag != NULLFRAG)
nextfrag->prev = tfp;
break;
case APPEND: /* Append to lastfrag */
append(&lastfrag->buf,bp);
lastfrag->last = last; /* Extend forward */
break;
case PREPEND: /* Prepend to nextfrag */
tbp = nextfrag->buf;
nextfrag->buf = bp;
append(&nextfrag->buf,tbp);
nextfrag->offset = offset; /* Extend backward */
break;
case (APPEND|PREPEND):
/* Consolidate by appending this fragment and nextfrag
* to lastfrag and removing the nextfrag descriptor
*/
append(&lastfrag->buf,bp);
append(&lastfrag->buf,nextfrag->buf);
nextfrag->buf = NULLBUF;
lastfrag->last = nextfrag->last;
/* Finally unlink and delete the now unneeded nextfrag */
lastfrag->next = nextfrag->next;
if(nextfrag->next != NULLFRAG)
nextfrag->next->prev = lastfrag;
freefrag(nextfrag);
break;
}
if(rp->fraglist->offset == 0 && rp->fraglist->next == NULLFRAG
&& rp->length != 0){
/* We've gotten a complete datagram, so extract it from the
* reassembly buffer and pass it on.
*/
bp = rp->fraglist->buf;
rp->fraglist->buf = NULLBUF;
ip->length = rp->length; /* Tell IP the entire length */
free_reasm(rp);
return bp;
} else
return NULLBUF;
}
static struct reasm *
lookup_reasm(ip)
struct ip_header *ip;
{
register struct reasm *rp;
for(rp = reasmq;rp != NULLREASM;rp = rp->next){
if(ip->source == rp->source && ip->dest == rp->dest
&& ip->protocol == rp->protocol && ip->id == rp->id)
return rp;
}
return NULLREASM;
}
#ifdef FOO
static
int16
hash_reasm(source,dest,protocol,id)
int32 source;
int32 dest,
char protocol;
int16 id;
{
register int16 hval;
hval = loword(source);
hval ^= hiword(source);
hval ^= loword(dest);
hval ^= hiword(dest);
hval ^= protocol & 0xff;
hval ^= id;
hval %= RHASH;
return hval;
}
#endif
/* Create a reassembly descriptor,
* put at head of reassembly list
*/
static struct reasm *
creat_reasm(ip)
register struct ip_header *ip;
{
register struct reasm *rp;
if((rp = (struct reasm *)calloc(1,sizeof(struct reasm))) == NULLREASM)
return rp; /* No space for descriptor */
rp->source = ip->source;
rp->dest = ip->dest;
rp->id = ip->id;
rp->protocol = ip->protocol;
rp->timer.start = TLB;
rp->timer.func = ip_timeout;
rp->timer.arg = (int *)rp;
rp->next = reasmq;
if(rp->next != NULLREASM)
rp->next->prev = rp;
reasmq = rp;
return rp;
}
/* Free all resources associated with a reassembly descriptor */
static void
free_reasm(rp)
register struct reasm *rp;
{
register struct frag *fp;
stop_timer(&rp->timer);
/* Remove from list of reassembly descriptors */
if(rp->prev != NULLREASM)
rp->prev->next = rp->next;
else
reasmq = rp->next;
if(rp->next != NULLREASM)
rp->next->prev = rp->prev;
/* Free any fragments on list, starting at beginning */
while((fp = rp->fraglist) != NULLFRAG){
rp->fraglist = fp->next;
free_p(fp->buf);
free((char *)fp);
}
free((char *)rp);
}
/* Handle reassembly timeouts by deleting all reassembly resources */
static void
ip_timeout(arg)
int *arg;
{
register struct reasm *rp;
rp = (struct reasm *)arg;
free_reasm(rp);
}
/* Create a fragment */
static
struct frag *
newfrag(offset,last,bp)
int16 offset,last;
struct mbuf *bp;
{
struct frag *fp;
if((fp = (struct frag *)calloc(1,sizeof(struct frag))) == NULLFRAG){
/* Drop fragment */
free_p(bp);
return NULLFRAG;
}
fp->buf = bp;
fp->offset = offset;
fp->last = last;
return fp;
}
/* Delete a fragment, return next one on queue */
static
void
freefrag(fp)
struct frag *fp;
{
free_p(fp->buf);
free((char *)fp);
}
#ifdef TRACE
int
doipstat(argc,argv)
int argc;
char *argv[];
{
extern struct ip_stats ip_stats;
extern struct reasm *reasmq;
register struct reasm *rp;
register struct frag *fp;
char *inet_ntoa();
printf("total %ld runt %u len err %u vers err %u",
ip_stats.total,ip_stats.runt,ip_stats.length,ip_stats.version);
printf(" chksum err %u badproto %u\r\n",
ip_stats.checksum,ip_stats.badproto);
if(reasmq != NULLREASM)
printf("Reassembly fragments:\r\n");
for(rp = reasmq;rp != NULLREASM;rp = rp->next){
printf("src %s",inet_ntoa(rp->source));
printf(" dest %s",inet_ntoa(rp->dest));
printf(" id %u pctl %u time %u len %u\r\n",
rp->id,rp->protocol,rp->timer.count,rp->length);
for(fp = rp->fraglist;fp != NULLFRAG;fp = fp->next){
printf(" offset %u last %u\r\n",fp->offset,fp->last);
}
}
return 0;
}
#endif
SHAR_EOF
cat << \SHAR_EOF > udp.c
/* Send and receive User Datagram Protocol packets */
#include "machdep.h"
#include "mbuf.h"
#include "netuser.h"
#include "udp.h"
#include "internet.h"
struct udp_cb *udps[NUDP]; /* Hash table for UDP structures */
struct udp_stat udp_stat; /* Statistics */
/* Create a UDP control block for lsocket, so that we can queue
* incoming datagrams.
*/
int
open_udp(lsocket,r_upcall)
struct socket *lsocket;
void (*r_upcall)();
{
char *malloc();
register struct udp_cb *up;
struct udp_cb *lookup_udp();
int16 hval,hash_udp();
if((up = lookup_udp(lsocket)) != NULLUDP)
return 0; /* Already exists */
if((up = (struct udp_cb *)malloc(sizeof (struct udp_cb))) == NULLUDP){
net_error = NO_SPACE;
return -1;
}
up->rcvq = NULLBUF;
up->rcvcnt = 0;
up->socket.address = lsocket->address;
up->socket.port = lsocket->port;
up->r_upcall = r_upcall;
hval = hash_udp(lsocket);
up->next = udps[hval];
up->prev = NULLUDP;
up->next->prev = up;
udps[hval] = up;
return 0;
}
/* Send a UDP datagram */
int
send_udp(lsocket,fsocket,tos,ttl,bp,length,id,df)
struct socket *lsocket; /* Source socket */
struct socket *fsocket; /* Destination socket */
char tos; /* Type-of-service for IP */
char ttl; /* Time-to-live for IP */
struct mbuf *bp; /* Data field, if any */
int16 length; /* Length of data field */
int16 id; /* Optional ID field for IP */
char df; /* Don't Fragment flag for IP */
{
struct mbuf *hbp;
int16 hdr_len;
struct pseudo_header ph;
struct udp_header *uhdr;
if(length == 0 && bp != NULLBUF)
length = len_mbuf(bp);
hdr_len = sizeof(struct udp_header);
length += hdr_len;
/* Allocate UDP protocol header and fill it in */
if((hbp = alloc_mbuf(hdr_len)) == NULLBUF){
net_error = NO_SPACE;
return -1;
}
hbp->cnt = hdr_len;
uhdr = (struct udp_header *)hbp->data;
uhdr->source = htons(lsocket->port);
uhdr->dest = htons(fsocket->port);
uhdr->length = htons(length);
uhdr->checksum = 0;
/* Link in the user data */
hbp->next = bp;
/* Create IP pseudo-header, compute checksum and send it */
ph.length = length;
ph.source = lsocket->address;
ph.dest = fsocket->address;
ph.protocol = UDP_PTCL;
ph.zero = 0;
/* All zeros and all ones is equivalent in one's complement arithmetic;
* the spec requires us to change zeros into ones to distinguish an
* all-zero checksum from no checksum at all
*/
if((uhdr->checksum = cksum(&ph,hbp,length)) == 0)
uhdr->checksum = 0xffffffff;
udp_stat.sent++;
ip_send(lsocket->address,fsocket->address,UDP_PTCL,tos,ttl,hbp,length,id,df);
return length;
}
/* Accept a waiting datagram, if available. Returns length of datagram */
int
recv_udp(lsocket,fsocket,bp)
struct socket *lsocket; /* Local socket to receive on */
struct socket *fsocket; /* Place to stash incoming socket */
struct mbuf **bp; /* Place to stash data packet */
{
struct udp_cb *lookup_udp();
register struct udp_cb *up;
struct socket *sp;
struct mbuf *buf;
int16 length;
up = lookup_udp(lsocket);
if(up == NULLUDP){
net_error = NO_CONN;
return -1;
}
if(up->rcvcnt == 0){
net_error = WOULDBLK;
return -1;
}
buf = dequeue(&up->rcvq);
up->rcvcnt--;
sp = (struct socket *)buf->data;
/* Fill in the user's foreign socket structure, if given */
if(fsocket != NULLSOCK){
fsocket->address = sp->address;
fsocket->port = sp->port;
}
/* Strip socket header and hand data to user */
pullup(&buf,NULLCHAR,sizeof(struct socket));
length = len_mbuf(buf);
if(bp != (struct mbuf **)NULL)
*bp = buf;
else
free_p(buf);
return length;
}
/* Delete a UDP control block */
int
del_udp(lsocket)
struct socket *lsocket;
{
register struct udp_cb *up;
struct udp_cb *lookup_udp();
struct mbuf *bp;
int16 hval;
if((up = lookup_udp(lsocket)) == NULLUDP){
net_error = INVALID;
return -1;
}
/* Get rid of any pending packets */
while(up->rcvcnt != 0){
bp = up->rcvq;
up->rcvq = up->rcvq->anext;
free_p(bp);
up->rcvcnt--;
}
hval = hash_udp(&up->socket);
if(udps[hval] == up){
/* First on list */
udps[hval] = up->next;
up->next->prev = NULLUDP;
} else {
up->prev->next = up->next;
up->next->prev = up->prev;
}
free((char *)up);
return 0;
}
/* Process an incoming UDP datagram */
void
udp_input(bp,protocol,source,dest,tos,length,rxbroadcast)
struct mbuf *bp;
char protocol;
int32 source; /* Source IP address */
int32 dest; /* Dest IP address */
char tos;
int16 length;
char rxbroadcast; /* The only protocol that accepts 'em */
{
struct pseudo_header ph;
struct udp_header udp;
struct udp_cb *up,*lookup_udp();
struct socket lsocket;
struct socket *fsocket;
struct mbuf *sp;
int ckfail = 0;
if(bp == NULLBUF)
return;
udp_stat.rcvd++;
/* Create pseudo-header and verify checksum */
ph.source = source;
ph.dest = dest;
ph.protocol = protocol;
ph.length = length;
ph.zero = 0;
if(cksum(&ph,bp,length) != 0)
/* Checksum apparently failed, note for later */
ckfail++;
/* Extract UDP header in host order */
pullup(&bp,(char *)&udp,sizeof(struct udp_header));
/* If the checksum field is zero, then ignore a checksum error.
* I think this is dangerously wrong, but it is in the spec.
*/
if(ckfail && udp.checksum != 0){
udp_stat.cksum++;
free_p(bp);
return;
}
udp.dest = ntohs(udp.dest);
udp.source = ntohs(udp.source);
/* If this was a broadcast packet, pretend it was sent to us */
if(rxbroadcast){
lsocket.address = ip_addr;
udp_stat.bdcsts++;
} else
lsocket.address = dest;
lsocket.port = udp.dest;
/* See if there's somebody around to read it */
if((up = lookup_udp(&lsocket)) == NULLUDP){
/* Nope, toss it on the floor */
udp_stat.unknown++;
free_p(bp);
return;
}
/* Create a buffer which will contain the foreign socket info */
if((sp = alloc_mbuf(sizeof(struct socket))) == NULLBUF){
/* No space, drop whole packet */
free_p(bp);
return;
}
sp->cnt = sizeof(struct socket);
fsocket = (struct socket *)sp->data;
fsocket->address = source;
fsocket->port = udp.source;
/* Yes, remove the now redundant UDP header, chain the foreign socket
* info in front of it and queue it
*/
sp->next = bp;
enqueue(&up->rcvq,sp);
up->rcvcnt++;
if(up->r_upcall)
(*up->r_upcall)(&lsocket,up->rcvcnt);
}
/* Look up UDP socket, return control block pointer or NULLUDP if nonexistant */
static
struct udp_cb *
lookup_udp(socket)
struct socket *socket;
{
register struct udp_cb *up;
int16 hash_udp();
up = udps[hash_udp(socket)];
while(up != NULLUDP){
if(bcmp((char *)socket,(char *)&up->socket,sizeof(struct socket)) == 0)
break;
up = up->next;
}
return up;
}
/* Hash a UDP socket (address and port) structure */
static
int16
hash_udp(socket)
struct socket *socket;
{
int16 hval;
/* Compute hash function on socket structure */
hval = hiword(socket->address);
hval ^= loword(socket->address);
hval ^= socket->port;
hval %= NUDP;
return hval;
}
#ifdef TRACE
/* Dump UDP statistics and control blocks */
doudpstat()
{
extern struct udp_stat udp_stat;
char *psocket();
register struct udp_cb *udp;
register int i;
printf("sent %u rcvd %u bdcsts %u cksum err %u unknown socket %u\r\n",
udp_stat.sent,udp_stat.rcvd,udp_stat.bdcsts,udp_stat.cksum,udp_stat.unknown);
#ifdef AMIGA
printf("&UCB Rcv-Q Local socket\r\n");
#else
printf("&UCB Rcv-Q Local socket\r\n");
#endif
for(i=0;i<NUDP;i++){
for(udp = udps[i];udp != NULLUDP; udp = udp->next){
#ifdef AMIGA
printf("%6lx%6u %s\r\n",(unsigned long)udp,udp->rcvcnt,
#else
printf("%x%6u %s\r\n",(int)udp,udp->rcvcnt,
#endif
psocket(&udp->socket));
}
}
}
/* Dump a UDP header */
void
udp_dump(bp,source,dest,check)
struct mbuf *bp;
int32 source,dest;
int check; /* If 0, bypass checksum verify */
{
register struct udp_header *udph;
struct pseudo_header ph;
int i;
char tmpbuf;
if(bp == NULLBUF)
return;
/* If packet isn't in a single buffer, make a temporary copy and
* note the fact so we free it later
*/
if(bp->next != NULLBUF){
bp = copy_p(bp,len_mbuf(bp));
tmpbuf = 1;
} else
tmpbuf = 0;
udph = (struct udp_header *)bp->data;
printf("UDP:");
printf(" %u->%u",ntohs(udph->source),
ntohs(udph->dest));
printf(" len %u",ntohs(udph->length));
if(check){
/* Verify checksum */
ph.source = source;
ph.dest = dest;
ph.zero = 0;
ph.protocol = UDP_PTCL;
ph.length = len_mbuf(bp);
if(udph->checksum != 0 && (i = cksum(&ph,bp,ph.length)) != 0)
printf(" CHECKSUM ERROR (%u)",i);
}
printf("\r\n");
if(tmpbuf)
free_p(bp);
}
#endif
SHAR_EOF
# End of shell archive
exit 0
--
Bob Page, U of Lowell CS Dept. page@swan.ulowell.edu ulowell!page
Have five nice days.